﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace MyGames
{

    // UPGRADE: FireShield & ImpactFlare & AuraOfFire animations
    class PlayerSkillManager
    {
        #region Skills components
        static Player player;
        public Skill[] skills;
        #endregion

        #region Constructor
        public PlayerSkillManager(Player owner, List<Enemy> enemies, ParticleManager particles)
        {
            player = owner;
            Skill.Initalize(owner, enemies, particles);

            skills = new Skill[6];
            skills[0] = new SkillAvatar();
            skills[1] = new SkillImpactFlare();
            skills[2] = new SkillAuraOfFire();
            skills[3] = new SkillFireShield();
            skills[4] = new SkillFlameExplosion();
            skills[5] = new SkillChaoticRift();
        }
        #endregion

        #region Update and Draw
        private void UpdateInput(GameTime gameTime)
        {
            if (EmuGamePad.IsEmuKeyTriggered(EmuButton.UseAvatar))
                skills[0].UseSkill(gameTime);

            if (EmuGamePad.IsEmuKeyTriggered(EmuButton.UseImpactFlare))
                skills[1].UseSkill(gameTime);

            if (EmuGamePad.IsEmuKeyTriggered(EmuButton.UseFireShield))
                skills[3].UseSkill(gameTime);

            if (EmuGamePad.IsEmuKeyTriggered(EmuButton.UseFlameExplosion))
                skills[4].UseSkill(gameTime);

            if (EmuGamePad.IsEmuKeyTriggered(EmuButton.UseChaoticRift))
                skills[5].UseSkill(gameTime);
        }

        public void Update(GameTime gameTime)
        {
            UpdateInput(gameTime);

            skills[0].Update(gameTime);
            skills[1].Update(gameTime);
            skills[2].Update(gameTime);
            skills[3].Update(gameTime);
            skills[4].Update(gameTime);
            skills[5].Update(gameTime);
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            skills[0].Draw(spriteBatch);
            skills[1].Draw(spriteBatch);
            skills[2].Draw(spriteBatch);
            skills[3].Draw(spriteBatch);
            skills[4].Draw(spriteBatch);
            skills[5].Draw(spriteBatch);
        }
        #endregion

        public int AvaiableSkillPoint
        {
            get { return player.SkillPoint; }
            set { player.SkillPoint = value; }
        }

        // Skill specific classes
        #region Skill Classes
        internal abstract class Skill : GameObject
        {
            static protected ContentManager content = GameLoader.Content;
            static protected Player owner;
            static protected List<Enemy> enemies;
            static protected ParticleManager particles;
            static public void Initalize(Player owner, List<Enemy> enemies, ParticleManager particles)
            {
                Skill.owner = owner;
                Skill.enemies = enemies;
                Skill.particles = particles;
            }

            #region Declaration
            protected int level;   // Save
            protected int mana;
            protected int manaPerLvl;
            protected int coolDown;
            protected int duration;
            protected int requirePerLvl = 2;

            protected bool avaiable = false;
            protected bool casting = false;
            protected float castTime;
            protected float nextActionTime = 0f;
            #endregion

            #region Properties
            public bool Avaiable { get { return avaiable; } }

            public int CurrentLevel
            {
                get { return level; }
                set
                {
                    level = value;
                }
            }

            public int NextLevelMana { get { return mana + manaPerLvl * (level + 1); } }

            public int Cooldown { get { return coolDown; } }

            public virtual int RequireLevel
            {
                get { return requirePerLvl * level; }
            }
            #endregion

            public void UseSkill(GameTime gameTime)
            {
                float requireMp = mana + manaPerLvl * level;
                if (!avaiable || casting || owner.Mana < requireMp) return;

                owner.Mana -= requireMp;
                castTime = (float)gameTime.TotalGameTime.TotalSeconds;
                avaiable = false;
                casting = true;

                Effect();
            }

            protected abstract void Effect();

            protected abstract void DeEffect();

            public bool LevelUp()
            {
                if (player.Level >= RequireLevel)
                {
                    if (level == 0) avaiable = true;
                    level++;

                    return true;
                }

                return false;
            }

            public abstract string GetInformation();

            public abstract string GetName();

            #region Draw and Update
            public override void Update(GameTime gameTime)
            {
                if (level <= 0) return;

                float time = (float)gameTime.TotalGameTime.TotalSeconds;
                if (time > castTime + coolDown)
                    avaiable = true;

                base.Update(gameTime);
            }

            public override void Draw(SpriteBatch spriteBatch)
            {
                if (!enabled)
                    return;
                if (animations.ContainsKey(currentAnimation))
                {
                    Vector2 og = new Vector2(animations[currentAnimation].FrameWidth / 2, animations[currentAnimation].FrameHeight / 2);
                    spriteBatch.Draw(
                        animations[currentAnimation].Texture,
                        Camera.WorldToScreen(WorldLocation),
                        animations[currentAnimation].FrameRectangle,
                        affectColor, 0f, og, scale, SpriteEffects.None, drawDepth);
                }
            }

            protected override Point offset()
            {
                return new Point(animations[currentAnimation].FrameWidth / 2, animations[currentAnimation].FrameHeight / 2);
            }
            #endregion
        }

        internal class SkillAvatar : Skill
        {
            private int _increaseValue;
            private float _scaleDeltaValue = 0.005f;

            public SkillAvatar()
            {
                // Information
                mana = 0; manaPerLvl = 0; level = 0;
                duration = 10; coolDown = 20;

                // Animation
                //Texture2D texture = content.Load<Texture2D>(Const.TexturePathSkill + "Avatar");
                //animations.Add("avatar", new AnimationStrip(texture, 2, 5, "avatar"));
                //drawDepth = 0.9f; enabled = false;
            }

            protected override void Effect()
            {
                // Value
                Calculate(level);
                owner.Strength += _increaseValue;

                // Animation
                worldLocation = owner.WorldCenter;
                owner.AffectColor = Color.Red;
                enabled = true;
                PlayAnimation("avatar", false, true, true);
            }

            protected override void DeEffect()
            {
                enabled = false;
                owner.Strength -= _increaseValue;
                owner.AffectColor = Color.White;
                owner.Scale = 1f;
                scale = 1f;
            }

            public override void Update(GameTime gameTime)
            {
                if (avaiable) return;
                base.Update(gameTime);
                if (!enabled) return;

                // Sound
                //if (animations[currentAnimation].CurrentFrame == 1)
                //    AudioManager.PlayCue("Avatar");

                // End effect
                float time = (float)gameTime.TotalGameTime.TotalSeconds;
                if (time > duration + castTime)
                {
                    casting = false;
                    DeEffect();
                }
                // Update effect
                else
                {
                    worldLocation = owner.WorldCenter;

                    //scale += _scaleDeltaValue * 2;
                    owner.Scale += _scaleDeltaValue;
                    if (owner.Scale > 1.2f || owner.Scale < 1f)
                        _scaleDeltaValue *= -1;
                }
            }

            private void Calculate(int level)
            {
                _increaseValue = owner.Level + 10 + 10 * level;
            }

            public override string GetInformation()
            {
                Calculate(level + 1);
                return "Description: Increase your strength by " + _increaseValue.ToString() +
                       " for " + duration.ToString() + " seconds.";
            }

            public override string GetName()
            {
                return "Avatar";
            }
        }

        internal class SkillImpactFlare : Skill
        {
            List<Enemy> effectedEnemies = new List<Enemy>();
            int range = 600;
            int damage;
            Vector2 castPosition;

            public SkillImpactFlare()
            {
                // Information
                mana = 25; manaPerLvl = 25; level = 0;
                duration = 3; coolDown = 8;

                // Animation
                Texture2D texture = content.Load<Texture2D>(Const.TexturePathSkill + "ImpactFlare");
                animations.Add("impactflare", new AnimationStrip(texture, 1, 5, "impactflare"));
                drawDepth = 0.9f; enabled = false;
            }

            protected override void Effect()
            {
                // Value
                Calculate(level);

                // Animation
                worldLocation = owner.WorldCenter;
                castPosition = worldLocation;

                Vector2 dir = new Vector2(1, 0); flipped = false;
                if (owner.FacingLeft) { dir.X = -1; flipped = true; }
                velocity = dir * range * 1f / duration;
                enabled = true;
                PlayAnimation("impactflare", false, true, true);
            }

            protected override void DeEffect()
            {
                enabled = false;
                casting = false;
                foreach (Enemy enemy in effectedEnemies)
                    enemy.AttackEffect = AttackEffect.Normal;

                effectedEnemies.Clear();
            }

            public override void Update(GameTime gameTime)
            {
                if (avaiable) return;
                base.Update(gameTime);
                if (!enabled) return;

                // Check collission
                foreach (Enemy enemy in enemies)
                {
                    if ((enemy.WorldLocation - castPosition).Length() < range &&
                        IsCollideWith(enemy, false) && !effectedEnemies.Contains(enemy))
                    {
                        enemy.GetDamage(damage);
                        enemy.AttackEffect = AttackEffect.Stun;
                        effectedEnemies.Add(enemy);
                        particles.AddParticle(AttackType.Magic, enemy, false);
                    }
                }

                // End project
                if ((worldLocation - castPosition).Length() > range || worldLocation.X == 0 ||
                    worldLocation.X >= Camera.WorldRectangle.Width - 2)
                    DeEffect();

                // Sound
                if (gameTime.TotalGameTime.TotalSeconds > nextActionTime)
                {
                    //AudioManager.PlayCue("ImpactFlare");
                    nextActionTime = (float)gameTime.TotalGameTime.TotalSeconds + 1.2f;
                }
            }

            private void Calculate(int level)
            {
                damage = owner.Strength * 2 + level * 100;
            }

            public override string GetInformation()
            {
                Calculate(level + 1);
                return "Description: Throw a burning sword in front of you. Enemies hitted " +
                       "by the \nsword lose " + damage.ToString() + " health and stun for " + duration.ToString() + " seconds.";
            }

            public override string GetName()
            {
                return "Impact Flare";
            }
        }

        internal class SkillAuraOfFire : Skill
        {
            int range = 150;
            int damage;
            float chance = 0.3f;

            public SkillAuraOfFire()
            {
                // Information
                mana = 0; manaPerLvl = 0; level = 0;
                duration = 3; coolDown = 0;

                // Animation
                //Texture2D texture = content.Load<Texture2D>(Const.TexturePathSkill + "AuraOfFire");
                //animations.Add("auraoffire", new AnimationStrip(texture, 3, 5, "auraoffire"));
                //drawDepth = 0.8f; enabled = false;

                //enabled = true;
                //scale = 1.2f;
                //PlayAnimation("auraoffire", false, true, false);
            }

            public new void UseSkill(GameTime gameTime)
            {
                if (level == 0) return;
                enabled = true;
                PlayAnimation("auraoffire", false, true, false);
            }

            protected override void Effect()
            {
                Calculate(level);
                worldLocation = owner.WorldLocation;
            }

            protected override void DeEffect()
            {
            }

            public override void Update(GameTime gameTime)
            {
                if (level == 0) return;
                float time = (float)gameTime.TotalGameTime.TotalSeconds;

                Effect();

                // Check collission
                if (time > nextActionTime)
                {
                    //AudioManager.PlayCue("AuraOfFire");

                    foreach (Enemy enemy in enemies)
                        if ((enemy.WorldLocation - worldLocation).Length() < range)
                        {
                            bool crit = RandomHelper.rand.NextDouble() < chance;
                            if (crit) damage *= 2;
                            enemy.GetDamage(damage);
                            particles.AddParticle(AttackType.Magic, enemy, crit);
                        }

                    nextActionTime = time + duration;
                }

                base.Update(gameTime);
            }

            private void Calculate(int level)
            {
                damage = (owner.Strength + owner.Intelligent * 2) / 10 + level * 80;
            }

            public override string GetInformation()
            {
                Calculate(level + 1);
                return "Description: An aura of fire that hurt all enemies in the range of " + range.ToString() +
                     " every \n" + duration.ToString() + " seconds. Enemies get hurt lose " + damage.ToString() + " health." +
                     " There' also " + (chance * 100).ToString() + "% chance to \ndouble the damage.";
            }

            public override string GetName()
            {
                return "Aura of Fire";
            }
        }

        internal class SkillFireShield : Skill
        {
            private int increasedArmor;
            private float increasedHealth;
            private int firstHealMultiply = 4;

            public SkillFireShield()
            {
                // Information
                mana = 90; manaPerLvl = 20; level = 0;
                duration = 10; coolDown = 25;

                // Animation
                //Texture2D texture = content.Load<Texture2D>(Const.TexturePathSkill + "Heal");
                //animations.Add("heal", new AnimationStrip(texture, 4, 5, "heal"));
                //texture = content.Load<Texture2D>(Const.TexturePathSkill + "FireShield");
                //animations.Add("fireshield", new AnimationStrip(texture, 4, 5, "fireshield"));
                //animations["heal"].NextAnimation = "fireshield";
                //animations["fireshield"].NextAnimation = "heal";

                //drawDepth = 0.9f; enabled = false;
            }

            protected override void Effect()
            {
                // Value
                Calculate(level);
                owner.Armor += increasedArmor;
                owner.Health += increasedHealth * firstHealMultiply;

                // Animation
                worldLocation = owner.WorldCenter;

                enabled = true;
                PlayAnimation("heal", false, false, true);
            }

            protected override void DeEffect()
            {
                enabled = false;
                owner.Armor -= increasedArmor;
                owner.AffectColor = Color.White;
            }

            public override void Update(GameTime gameTime)
            {
                if (avaiable) return;
                base.Update(gameTime);
                if (!enabled) return;

                worldLocation = owner.WorldCenter;

                // End effect
                float time = (float)gameTime.TotalGameTime.TotalSeconds;
                if (time > duration + castTime)
                {
                    casting = false;
                    DeEffect();
                }

                // Update effect
                owner.Health += (increasedHealth * (float)gameTime.ElapsedGameTime.TotalSeconds);

                // Sound
                //if (animations[currentAnimation].FinishedPlaying)
                //    AudioManager.PlayCue("FireShield");
            }

            private void Calculate(int level)
            {
                increasedHealth = ((owner.Strength + owner.Intelligent) / 20f + level * 2) * 25;
                increasedArmor = Math.Min(70, level * 5 + owner.Agility / 10);
            }

            public override string GetInformation()
            {
                Calculate(level + 1);
                return "Description: Active a fire shield that heal " + (increasedHealth * firstHealMultiply).ToString() +
                       " HP and " + increasedHealth.ToString() + "/second, also \nincrease your armor by " + increasedArmor.ToString() +
                       ". The shield last for " + duration.ToString() + " seconds.";
            }

            public override string GetName()
            {
                return "Fire Shield";
            }
        }

        internal class SkillFlameExplosion : Skill
        {
            List<Enemy> effectedEnemies = new List<Enemy>();
            int range = 200;
            int damage;

            public SkillFlameExplosion()
            {
                // Information
                mana = 70; manaPerLvl = 40; level = 0;
                duration = 4; coolDown = 20;

                // Animation
                //Texture2D texture = content.Load<Texture2D>(Const.TexturePathSkill + "FlameExplosion");
                //animations.Add("flameexplosion", new AnimationStrip(texture, 2, 5, "flameexplosion"));
                //animations["flameexplosion"].FrameLength = 0.02f;
                //drawDepth = 0.9f; enabled = false;
            }

            protected override void Effect()
            {
                // Value
                Calculate(level);

                // Animation
                worldLocation = owner.WorldCenter;

                enabled = true;
                PlayAnimation("flameexplosion", false, true, true);
            }

            protected override void DeEffect()
            {
                scale = 1f;
                foreach (Enemy enemy in effectedEnemies)
                    enemy.AttackEffect = AttackEffect.Normal;

                effectedEnemies.Clear();
            }

            public override void Update(GameTime gameTime)
            {
                if (avaiable) return;
                base.Update(gameTime);
                if (!enabled && !casting) return;

                float time = (float)gameTime.TotalGameTime.TotalSeconds;

                // Animation
                worldLocation = owner.WorldCenter;
                if (time > nextActionTime)
                {
                    nextActionTime = time + 0.2f;
                    scale += 0.2f;
                    if (scale > 4f)
                    {
                        enabled = false;
                        DeEffect();
                    }
                }

                // Sound
                //if (animations[currentAnimation].CurrentFrame == 1)
                //    AudioManager.PlayCue("Explosion" + RandomHelper.rand.Next(1, 6).ToString());

                // Check collission
                foreach (Enemy enemy in enemies)
                {
                    if ((enemy.WorldLocation - worldLocation).Length() < range && !effectedEnemies.Contains(enemy))
                    {
                        enemy.AttackEffect = AttackEffect.Stun;
                        enemy.GetDamage(damage);
                        particles.AddParticle(AttackType.Magic, enemy, false);
                        effectedEnemies.Add(enemy);
                    }
                }

                // End effect
                if (time > castTime + duration)
                {
                    casting = false;
                    DeEffect();
                }
            }

            private void Calculate(int level)
            {
                damage = owner.Strength * 2 + owner.Intelligent * 5 + base.level * 80;
            }

            public override string GetInformation()
            {
                Calculate(level + 1);
                return "Description: Cause the area of " + range.ToString() + " around you explode. All enemies inside " +
                       "\nget " + damage.ToString() + " damage and stun for " + duration.ToString() + " seconds.";
            }

            public override string GetName()
            {
                return "Flame Explosion";
            }
        }

        internal class SkillChaoticRift : Skill
        {
            List<Enemy> effectedEnemies = new List<Enemy>();
            float aPreduction = 0.1f;
            int damage;

            public SkillChaoticRift()
            {
                // Information
                mana = 300; manaPerLvl = 100; level = 0;
                duration = 20; coolDown = 180;
                requirePerLvl = 10;

                // Animation
                //Texture2D texture = content.Load<Texture2D>(Const.TexturePathSkill + "ChaoticRift");
                //animations.Add("chaoticrift1", new AnimationStrip(texture, 6, 5, "chaoticrift1"));
                //texture = content.Load<Texture2D>(Const.TexturePathSkill + "FlameExplosion");
                //animations.Add("chaoticrift2", new AnimationStrip(texture, 3, 5, "chaoticrift2"));

                //drawDepth = 0.9f; enabled = false;
            }

            protected override void Effect()
            {
                // Value
                damage = (owner.Strength + owner.Intelligent) * 10 + level * 500;

                // Animation
                worldLocation = owner.WorldCenter;
                enabled = true;
                PlayAnimation("chaoticrift1", false, true, true);
            }

            protected override void DeEffect()
            {
                scale = 1f;
                foreach (Enemy enemy in effectedEnemies)
                {
                    enemy.AttackPower = (int)(enemy.AttackPower / aPreduction);
                    enemy.AttackEffect = AttackEffect.Normal;
                }
                effectedEnemies.Clear();
            }

            public override void Update(GameTime gameTime)
            {
                if (avaiable) return;
                base.Update(gameTime);
                if (!enabled && !casting) return;

                float time = (float)gameTime.TotalGameTime.TotalSeconds;

                // Sound
                //if (animations[currentAnimation].CurrentFrame == 1)
                //    AudioManager.PlayCue("Explosion" + RandomHelper.rand.Next(1, 6).ToString());

                // Animation
                if (time > nextActionTime)
                {
                    worldLocation = owner.WorldCenter;

                    // First state
                    if (currentAnimation == "chaoticrift1")
                    {
                        nextActionTime = time + 0.02f;
                        scale += 0.02f;

                        if (scale > 8f)
                        {
                            scale = 1;
                            PlayAnimation("chaoticrift2", false, true, false);
                        }
                    }
                    // Second state
                    else
                    {
                        int rx = RandomHelper.rand.Next(400) - 200;
                        int ry = RandomHelper.rand.Next(400) - 200;
                        float rscale = (float)RandomHelper.rand.NextDouble();
                        worldLocation.X = owner.WorldLocation.X + rx;
                        worldLocation.Y = owner.WorldLocation.Y + ry;
                        scale = 10 + rscale;
                    }
                }

                if (time > castTime + duration / 1.4)
                {
                    enabled = false;

                    // End effect
                    if (time > castTime + duration)
                    {
                        casting = false;
                        DeEffect();
                    }
                }

                // Check collission
                foreach (Enemy enemy in enemies)
                {
                    if (IsCollideWith(enemy, false) && !effectedEnemies.Contains(enemy))
                    {
                        // Effect
                        enemy.AttackPower = (int)(enemy.AttackPower * aPreduction);
                        enemy.GetDamage(damage);
                        enemy.AttackEffect = AttackEffect.Burn;

                        particles.AddParticle(AttackType.Magic, enemy, true);
                        effectedEnemies.Add(enemy);
                    }
                }

            }

            private void Calculate(int level)
            {
                damage = (owner.Strength + owner.Intelligent) * 10 + level * 500;
            }

            public override string GetInformation()
            {
                Calculate(level + 1);
                return "Description: Phodom's ultimate. When active, all Phodom's inner strength \nexplode" +
                       " and cover a large area around him with holy fire. All enemies inside \nget " + damage.ToString() +
                       " damages. Enemies survive the explosion will be burned 1% HP \nper second and lose " +
                       ((1f - aPreduction) * 100).ToString() + "% Attack power for " + (duration / 2).ToString() + " seconds.";
            }

            public override string GetName()
            {
                return "Chaotic Rift";
            }

            public override int RequireLevel
            {
                get
                {
                    return base.RequireLevel + requirePerLvl;
                }
            }
        }
        #endregion
    }
}